
#ifndef _TTG_PIPELINE_BASIC_PIPELINE_
#define _TTG_PIPELINE_BASIC_PIPELINE_
#include "Common/Definitions.h"

#include "vector"
#include "Common/Structures.h"

#include "Nodes/NodeManager.h"
#include "TaskGatherers.h"

namespace ttg_internal
{
	namespace pipeline
	{
		//Wrapper for bool, that have "right" default constructor.
		struct InitializableBool
		{
			bool value;

			inline InitializableBool()
			{ this->value = false; }

			inline InitializableBool(bool value)
			{ this->value = value; }

			inline operator bool()
			{ return value; }
		};
		//Base class for any pipeline. Defines common methods.
		template <class InType, class OutType,
				  class FirstNodeType, class LastNodeType>
		class BasicPipeline :public ttg::structures::NamedObject,
							 public IPipeline
		{
			private:
				ttg::pipeline::ContextMap<InitializableBool> is_started;
				ttg_internal::pipeline::InternalContext icontext;
				ttg_internal::pipeline::NodeManager<InType, OutType,
													FirstNodeType, LastNodeType> manager;
			protected:
				//Returns internal content for this pipeline set.
				inline ttg_internal::pipeline::InternalContext &getIContext()
				{ return icontext; }
				//Returns manager for nodes.
				inline ttg_internal::pipeline::NodeManager<InType, OutType,
														   FirstNodeType, LastNodeType> &getManager()
				{ return manager; }
				//Starts iteration (calls startIteration for the first node).
				void startIteration(ttg::structures::Enumerator<InType> &data,
									ttg::pipeline::ContextID ID)
				{
					if (!(bool)is_started[ID])
					{
						//Task gatherer for delayed tasks.
						ttg_internal::pipeline::BufferedTaskGatherer task_gatherer;
						icontext.setTaskGatherer(&task_gatherer, ID);
						//Starting iteration.
						manager.getPipelineStart().startIteration(ID);
						manager.getPipelineStart().getState(ID).getLocker().enter();
						manager.getPipelineStart().getState(ID).getActiveInputCount() += 1;	//due to fake first node
						manager.getPipelineStart().getState(ID).getLocker().leave();
						//Setting default task gatherer.
						icontext.setTaskGatherer(ttg::services::TaskScheduler::getRef(), ID);
						((ttg::services::ITaskScheduler<ttg::services::WiseTask *> *)ttg::services::TaskScheduler::getRef())
							->addTasks(task_gatherer.getGatheredTasks());
						task_gatherer.clearGatheredTasks();
						is_started[ID] = true;
					}
					((ttg::services::ITaskScheduler<ttg::services::WiseTask *> *)ttg::services::TaskScheduler::getRef())
						->addTasks(manager.getPipelineStart().packData(data, ID));
				}
				//Finishes iteration (calls finishIteration for the first node).
				void finishIteration(ttg::pipeline::ContextID ID)
				{
					//Finishing.
					manager.getPipelineStart().finishIteration(ID);
					is_started[ID] = false;
				}
				//Creates pipeline for required nodes.
				//The first and the last nodes will be added automatically.
				inline BasicPipeline(ttg::pipeline::NodeWrapper<InType, OutType> &wrapper,
									 const char *name)
					:NamedObject(name), manager(wrapper)
				{
					//Setting context.
					icontext.setTaskGatherer(ttg::services::TaskScheduler::getRef(),
											 icontext.getRootContextID());
					icontext.setPipelineEnumeration(&manager.getNodes());
					//Configuring nodes.
					std::vector<ttg_internal::pipeline::NavigatorNode *> &en = manager.getNodes();
					for (size_t i = 0; i < en.size(); i++)
					{
						en[i]->setContext(&icontext);
					}
				}
				//IPipeline member. Notifies nodes about pipeline recreation.
				virtual void onPipelineRecreation()
				{
					std::vector<ttg_internal::pipeline::NavigatorNode *> &en = manager.getNodes();
					for (size_t i = 0; i < en.size(); i++)
					{
						en[i]->onPipelineRecreation();
					}
				}
		};
	}
}

#endif
